R provides several classes for representing time series objects for a
variety of applications. Among those classes, ts is one of
the main formats for time series data in R, mainly due to its simplicity
and the wide adoption of this class by the main packages in R for time
series analysis, for example, the forecast and
stats packages.
The attributes of the ts class
A regular time series is defined as an ordered sequence of
observations over time, which is captured at equally spaced time
intervals. Whenever this condition ceases to exist, the series becomes
an irregular time series. The main characteristics of regular time
series data is as follows:
Cycle/period: a regular unit of time that split the series into
consecutive and equally long subsets
frequency: defines the length or the number of units of the
cycle
timestamp: provides the time each observation in the series was
captured, and can be used as the series index.
A ts object is composed of two elements - the series
values and its corresponding timestamp.
# number of observaitions
length(ngc)
[1] 76
We can look at the structure of a ts dataset with the
head() function:
ngc
Qtr1 Qtr2 Qtr3 Qtr4
2000 2050.6 1513.1 1475.0 2587.5
2001 2246.6 1444.4 1494.1 2120.2
2002 2258.4 1591.4 1542.2 2378.9
2003 2197.9 1368.4 1428.6 2263.7
2004 2100.9 1483.7 1482.2 2327.7
2005 2205.8 1534.1 1422.5 2326.4
2006 2126.4 1550.9 1462.1 2122.8
2007 2128.9 1555.2 1590.5 2399.2
2008 2278.2 1604.3 1460.9 2399.7
2009 2170.7 1527.8 1575.0 2491.9
2010 2142.9 1649.5 1637.5 2714.1
2011 2230.5 1657.3 1655.6 2541.9
2012 2127.8 1868.4 1807.2 2503.9
2013 2521.1 1742.9 1767.0 2920.8
2014 2557.9 1745.4 1809.3 2679.2
2015 2591.3 1899.9 1901.3 2588.2
2016 2356.3 2000.7 1947.8 2866.3
2017 2523.3 1910.4 1920.5 3086.0
2018 2796.7 2063.1 2156.1 2999.5
Here the rows represent the number of the cycle and the columns
represent the cycle units. For the ngc data, each calendar
year is a full cycle and the quarters are the cycle units.
The cycle() and the time() functions from
the stats package provide the cycle units and the
timestamp of each observation in the series:
cycle(ngc)
Qtr1 Qtr2 Qtr3 Qtr4
2000 1 2 3 4
2001 1 2 3 4
2002 1 2 3 4
2003 1 2 3 4
2004 1 2 3 4
2005 1 2 3 4
2006 1 2 3 4
2007 1 2 3 4
2008 1 2 3 4
2009 1 2 3 4
2010 1 2 3 4
2011 1 2 3 4
2012 1 2 3 4
2013 1 2 3 4
2014 1 2 3 4
2015 1 2 3 4
2016 1 2 3 4
2017 1 2 3 4
2018 1 2 3 4
time(ngc)
Qtr1 Qtr2 Qtr3 Qtr4
2000 2000.00 2000.25 2000.50 2000.75
2001 2001.00 2001.25 2001.50 2001.75
2002 2002.00 2002.25 2002.50 2002.75
2003 2003.00 2003.25 2003.50 2003.75
2004 2004.00 2004.25 2004.50 2004.75
2005 2005.00 2005.25 2005.50 2005.75
2006 2006.00 2006.25 2006.50 2006.75
2007 2007.00 2007.25 2007.50 2007.75
2008 2008.00 2008.25 2008.50 2008.75
2009 2009.00 2009.25 2009.50 2009.75
2010 2010.00 2010.25 2010.50 2010.75
2011 2011.00 2011.25 2011.50 2011.75
2012 2012.00 2012.25 2012.50 2012.75
2013 2013.00 2013.25 2013.50 2013.75
2014 2014.00 2014.25 2014.50 2014.75
2015 2015.00 2015.25 2015.50 2015.75
2016 2016.00 2016.25 2016.50 2016.75
2017 2017.00 2017.25 2017.50 2017.75
2018 2018.00 2018.25 2018.50 2018.75
A more concise way to get this information is with the
frequency() and deltat() functions:
deltat(ngc)
[1] 0.25
Other useful functions are start() and
end():
start(ngc)
[1] 2000 1
end(ngc)
[1] 2018 4
The ts_info() function from the TStudio
package provides a concise summary of most of the functions above.
ts_info(ngc)
The ngc series is a ts object with 1 variable and 76 observations
Frequency: 4
Start time: 2000 1
End time: 2018 4
Multivariate time series objects
When you have multivariate time series data, you need to use the
mts (multiple time series) class. This combines the
functionality of the ts and matrix
classes.
ts_info(Coffee_Prices)
The Coffee_Prices series is a mts object with 2 variables and 701 observations
Frequency: 12
Start time: 1960 1
End time: 2018 5
Creating a ts object
my_ts1 <- ts(data = 1:60,
start = c(2010, 1),
end = c(2014, 12),
frequency = 12)
ts_info(my_ts1)
The my_ts1 series is a ts object with 1 variable and 60 observations
Frequency: 12
Start time: 2010 1
End time: 2014 12
my_ts1
Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec
2010 1 2 3 4 5 6 7 8 9 10 11 12
2011 13 14 15 16 17 18 19 20 21 22 23 24
2012 25 26 27 28 29 30 31 32 33 34 35 36
2013 37 38 39 40 41 42 43 44 45 46 47 48
2014 49 50 51 52 53 54 55 56 57 58 59 60
Now we will work through the typical process of converting data from
a data.frame to a ts object.
str(US_indicators)
'data.frame': 528 obs. of 3 variables:
$ Date : Date, format: "1976-01-31" "1976-02-29" "1976-03-31" "1976-04-30" ...
$ Vehicle Sales : num 885 995 1244 1191 1203 ...
$ Unemployment Rate: num 8.8 8.7 8.1 7.4 6.8 8 7.8 7.6 7.4 7.2 ...
For now, we will only convert the vehicle sales into a
ts object.
Next, we need to define the start or end of the series. In this case,
the series started in January 1976 so we can define it as
start = c(1976, 1). Or we can write code to capture the
starting point.
start_point
[1] 1976 1
Now we build the series:
One of the main limitations of the ts class is that it
can only support two input elements for the timestamp. For example, when
we converted tvs into a ts object, we lost the
day component because ts could only store the month and
year.
Creating an mts object
ts_info(US_indicators_ts)
The US_indicators_ts series is a mts object with 2 variables and 528 observations
Frequency: 12
Start time: 1976 1
End time: 2019 12
Setting the series frequency
Setting the frequency of a series sets the length of a cycle.
\[
\text{Frequency} = \frac{\text{cycle length}}{\text{time interval
between observation}}
\]
In this example we will see how setting the frequency impacts the
structure of the ts object output. First, we simulate close
to ten years of daily data.
str(daily_df)
'data.frame': 3650 obs. of 2 variables:
$ date: Date, format: "2010-01-01" "2010-01-02" "2010-01-03" "2010-01-04" ...
$ y : num 14 11.9 16.4 12.8 13.8 ...
Create ts object:
ts_info(days_week_ts)
The days_week_ts series is a mts object with 2 variables and 3650 observations
Frequency: 7
Start time: 1 6
End time: 523 1
Data manipulation of ts objects
The window function
The main purpose of a window function is to subset a ts
object based on a time range. The main argument of the
window() function are the start and
end arguments. Let’s use the window() function
to extract all the observations of the year 2005 from the NGC
series:
window(ngc, start = c(2005, 1), end = c(2005, 4))
Qtr1 Qtr2 Qtr3 Qtr4
2005 2205.8 1534.1 1422.5 2326.4
We can also extract a specific frequency unit from the series. Say
we’re interested in extracting all the observations of the series that
occurred in the third quarter of the year. This can be done by setting
the starting point at the third quarter of the first year and the
frequency to 1.
window(ngc, start = c(2000, 3), frequency = 1)
Time Series:
Start = 2000.5
End = 2018.5
Frequency = 1
[1] 1475.0 1494.1 1542.2 1428.6 1482.2 1422.5 1462.1 1590.5 1460.9 1575.0 1637.5 1655.6 1807.2 1767.0 1809.3 1901.3 1947.8 1920.5 2156.1
Aggregating ts objects
The aggregate() function splits the data into subsets,
computes specific summary statistics, and then aggregates the results to
a ts or data.frame object. Let’s use
aggregate() to transform the NGC series from a quarterly
frequency to yearly:
1+1
[1] 2
Creating lags and leads for ts objects
The lag() function from the stats
package (this should not be confused with the lag()
function from the dplyr package) can be used to create
lags or leads for ts objects.
ts_info(ngc_lag4)
The ngc_lag4 series is a ts object with 1 variable and 76 observations
Frequency: 4
Start time: 2001 1
End time: 2019 4
LS0tCnRpdGxlOiAiQ2hhcHRlciAyOiBUaGUgVGltZSBTZXJpZXMgT2JqZWN0IgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgpSIHByb3ZpZGVzIHNldmVyYWwgY2xhc3NlcyBmb3IgcmVwcmVzZW50aW5nIHRpbWUgc2VyaWVzIG9iamVjdHMgZm9yIGEgdmFyaWV0eSBvZiBhcHBsaWNhdGlvbnMuIEFtb25nIHRob3NlIGNsYXNzZXMsIGB0c2AgaXMgb25lIG9mIHRoZSBtYWluIGZvcm1hdHMgZm9yIHRpbWUgc2VyaWVzIGRhdGEgaW4gUiwgbWFpbmx5IGR1ZSB0byBpdHMgc2ltcGxpY2l0eSBhbmQgdGhlIHdpZGUgYWRvcHRpb24gb2YgdGhpcyBjbGFzcyBieSB0aGUgbWFpbiBwYWNrYWdlcyBpbiBSIGZvciB0aW1lIHNlcmllcyBhbmFseXNpcywgZm9yIGV4YW1wbGUsIHRoZSBgZm9yZWNhc3RgIGFuZCBgc3RhdHNgIHBhY2thZ2VzLgoKIyBUaGUgTmF0dXJhbCBHYXMgQ29uc3VtcHRpb24gZGF0YXNldAoKYGBge3J9CmxpYnJhcnkocGFjbWFuKQpwX2xvYWQoUXVhbmRsKQoKbmdjIDwtIFF1YW5kbChjb2RlID0gIkZSRUQvTkFUVVJBTEdBUyIsCiAgICAgICAgICAgICAgY29sbGFwc2UgPSAicXVhcnRlcmx5IiwKICAgICAgICAgICAgICB0eXBlID0gInRzIiwKICAgICAgICAgICAgICBlbmRfZGF0ZSA9ICIyMDE4LTEyLTMxIikKCmNsYXNzKG5nYykKYGBgCgpUaGUgc2ltcGxlc3QgbWV0aG9kIHRvIHBsb3QgYSBgdHNgIG9iamVjdCBpcyB3aXRoIHRoZSBgcGxvdGAgZnVuY3Rpb246CgpgYGB7cn0KcGxvdC50cyhuZ2MsCiAgICAgICAgbWFpbiA9ICJVUyBRdWFydGVybHkgTmF0dXJhbCBHYXMgQ29uc3VtcHRpb24iLAogICAgICAgIHlsYWIgPSAiQmlsbGlvbiBvZiBDdWJpYyBGZWV0IikKYGBgCgojIFRoZSBhdHRyaWJ1dGVzIG9mIHRoZSBgdHNgIGNsYXNzCgpBIHJlZ3VsYXIgdGltZSBzZXJpZXMgaXMgZGVmaW5lZCBhcyBhbiBvcmRlcmVkIHNlcXVlbmNlIG9mIG9ic2VydmF0aW9ucyBvdmVyIHRpbWUsIHdoaWNoIGlzIGNhcHR1cmVkIGF0IGVxdWFsbHkgc3BhY2VkIHRpbWUgaW50ZXJ2YWxzLiBXaGVuZXZlciB0aGlzIGNvbmRpdGlvbiBjZWFzZXMgdG8gZXhpc3QsIHRoZSBzZXJpZXMgYmVjb21lcyBhbiBpcnJlZ3VsYXIgdGltZSBzZXJpZXMuIFRoZSBtYWluIGNoYXJhY3RlcmlzdGljcyBvZiByZWd1bGFyIHRpbWUgc2VyaWVzIGRhdGEgaXMgYXMgZm9sbG93czoKCi0gICBDeWNsZS9wZXJpb2Q6IGEgcmVndWxhciB1bml0IG9mIHRpbWUgdGhhdCBzcGxpdCB0aGUgc2VyaWVzIGludG8gY29uc2VjdXRpdmUgYW5kIGVxdWFsbHkgbG9uZyBzdWJzZXRzCgotICAgZnJlcXVlbmN5OiBkZWZpbmVzIHRoZSBsZW5ndGggb3IgdGhlIG51bWJlciBvZiB1bml0cyBvZiB0aGUgY3ljbGUKCi0gICB0aW1lc3RhbXA6IHByb3ZpZGVzIHRoZSB0aW1lIGVhY2ggb2JzZXJ2YXRpb24gaW4gdGhlIHNlcmllcyB3YXMgY2FwdHVyZWQsIGFuZCBjYW4gYmUgdXNlZCBhcyB0aGUgc2VyaWVzIGluZGV4LgoKQSBgdHNgIG9iamVjdCBpcyBjb21wb3NlZCBvZiB0d28gZWxlbWVudHMgLSB0aGUgc2VyaWVzIHZhbHVlcyBhbmQgaXRzIGNvcnJlc3BvbmRpbmcgdGltZXN0YW1wLgoKYGBge3J9CiMgbnVtYmVyIG9mIG9ic2VydmFpdGlvbnMKbGVuZ3RoKG5nYykKYGBgCgpXZSBjYW4gbG9vayBhdCB0aGUgc3RydWN0dXJlIG9mIGEgYHRzYCBkYXRhc2V0IHdpdGggdGhlIGBoZWFkKClgIGZ1bmN0aW9uOgoKYGBge3J9Cm5nYwpgYGAKCkhlcmUgdGhlIHJvd3MgcmVwcmVzZW50IHRoZSBudW1iZXIgb2YgdGhlIGN5Y2xlIGFuZCB0aGUgY29sdW1ucyByZXByZXNlbnQgdGhlIGN5Y2xlIHVuaXRzLiBGb3IgdGhlIGBuZ2NgIGRhdGEsIGVhY2ggY2FsZW5kYXIgeWVhciBpcyBhIGZ1bGwgY3ljbGUgYW5kIHRoZSBxdWFydGVycyBhcmUgdGhlIGN5Y2xlIHVuaXRzLgoKVGhlIGBjeWNsZSgpYCBhbmQgdGhlIGB0aW1lKClgIGZ1bmN0aW9ucyBmcm9tIHRoZSAqKnN0YXRzKiogcGFja2FnZSBwcm92aWRlIHRoZSBjeWNsZSB1bml0cyBhbmQgdGhlIHRpbWVzdGFtcCBvZiBlYWNoIG9ic2VydmF0aW9uIGluIHRoZSBzZXJpZXM6CgpgYGB7cn0KY3ljbGUobmdjKQoKdGltZShuZ2MpCmBgYAoKQSBtb3JlIGNvbmNpc2Ugd2F5IHRvIGdldCB0aGlzIGluZm9ybWF0aW9uIGlzIHdpdGggdGhlIGBmcmVxdWVuY3koKWAgYW5kIGBkZWx0YXQoKWAgZnVuY3Rpb25zOgoKYGBge3J9CmZyZXF1ZW5jeShuZ2MpCgpkZWx0YXQobmdjKQpgYGAKCk90aGVyIHVzZWZ1bCBmdW5jdGlvbnMgYXJlIGBzdGFydCgpYCBhbmQgYGVuZCgpYDoKCmBgYHtyfQpzdGFydChuZ2MpCgplbmQobmdjKQpgYGAKClRoZSBgdHNfaW5mbygpYCBmdW5jdGlvbiBmcm9tIHRoZSAqKlRTdHVkaW8qKiBwYWNrYWdlIHByb3ZpZGVzIGEgY29uY2lzZSBzdW1tYXJ5IG9mIG1vc3Qgb2YgdGhlIGZ1bmN0aW9ucyBhYm92ZS4KCmBgYHtyfQpwX2xvYWQoVFNzdHVkaW8pCgp0c19pbmZvKG5nYykKYGBgCgojIyBNdWx0aXZhcmlhdGUgdGltZSBzZXJpZXMgb2JqZWN0cwoKV2hlbiB5b3UgaGF2ZSBtdWx0aXZhcmlhdGUgdGltZSBzZXJpZXMgZGF0YSwgeW91IG5lZWQgdG8gdXNlIHRoZSBgbXRzYCAobXVsdGlwbGUgdGltZSBzZXJpZXMpIGNsYXNzLiBUaGlzIGNvbWJpbmVzIHRoZSBmdW5jdGlvbmFsaXR5IG9mIHRoZSBgdHNgIGFuZCBgbWF0cml4YCBjbGFzc2VzLgoKYGBge3J9CmRhdGEoIkNvZmZlZV9QcmljZXMiKQpoZWFkKENvZmZlZV9QcmljZXMpCgp0c19pbmZvKENvZmZlZV9QcmljZXMpCmBgYAoKIyMgQ3JlYXRpbmcgYSBgdHNgIG9iamVjdAoKYGBge3J9Cm15X3RzMSA8LSB0cyhkYXRhID0gMTo2MCwKICAgICAgICAgICAgIHN0YXJ0ID0gYygyMDEwLCAxKSwKICAgICAgICAgICAgIGVuZCA9IGMoMjAxNCwgMTIpLAogICAgICAgICAgICAgZnJlcXVlbmN5ID0gMTIpCgp0c19pbmZvKG15X3RzMSkKCm15X3RzMQpgYGAKCk5vdyB3ZSB3aWxsIHdvcmsgdGhyb3VnaCB0aGUgdHlwaWNhbCBwcm9jZXNzIG9mIGNvbnZlcnRpbmcgZGF0YSBmcm9tIGEgYGRhdGEuZnJhbWVgIHRvIGEgYHRzYCBvYmplY3QuCgpgYGB7cn0KbGlicmFyeSh0aWR5dmVyc2UpCgojIGxvYWQgdGhlIGRhdGEKZGF0YSgiVVNfaW5kaWNhdG9ycyIpCnN0cihVU19pbmRpY2F0b3JzKQpgYGAKCkZvciBub3csIHdlIHdpbGwgb25seSBjb252ZXJ0IHRoZSB2ZWhpY2xlIHNhbGVzIGludG8gYSBgdHNgIG9iamVjdC4KCmBgYHtyfQp0dnMgPC0gCiAgVVNfaW5kaWNhdG9ycyAlPiUgCiAgc2VsZWN0KERhdGUsIGBWZWhpY2xlIFNhbGVzYCkgJT4lIAogIGFycmFuZ2UoRGF0ZSkKCmhlYWQodHZzKQpgYGAKCk5leHQsIHdlIG5lZWQgdG8gZGVmaW5lIHRoZSBzdGFydCBvciBlbmQgb2YgdGhlIHNlcmllcy4gSW4gdGhpcyBjYXNlLCB0aGUgc2VyaWVzIHN0YXJ0ZWQgaW4gSmFudWFyeSAxOTc2IHNvIHdlIGNhbiBkZWZpbmUgaXQgYXMgYHN0YXJ0ID0gYygxOTc2LCAxKWAuIE9yIHdlIGNhbiB3cml0ZSBjb2RlIHRvIGNhcHR1cmUgdGhlIHN0YXJ0aW5nIHBvaW50LgoKYGBge3J9CmxpYnJhcnkobHVicmlkYXRlKQoKc3RhcnRfcG9pbnQgPC0gYyh5ZWFyKG1pbih0dnMkRGF0ZSkpLCBtb250aChtaW4odHZzJERhdGUpKSkKc3RhcnRfcG9pbnQKYGBgCgpOb3cgd2UgYnVpbGQgdGhlIHNlcmllczoKCmBgYHtyfQp0dnNfdHMgPC0gdHMoZGF0YSA9IHR2cyRgVmVoaWNsZSBTYWxlc2AsCiAgICAgICAgICAgICBzdGFydCA9IHN0YXJ0X3BvaW50LAogICAgICAgICAgICAgZnJlcXVlbmN5ID0gMTIpCmBgYAoKT25lIG9mIHRoZSBtYWluIGxpbWl0YXRpb25zIG9mIHRoZSBgdHNgIGNsYXNzIGlzIHRoYXQgaXQgY2FuIG9ubHkgc3VwcG9ydCB0d28gaW5wdXQgZWxlbWVudHMgZm9yIHRoZSB0aW1lc3RhbXAuIEZvciBleGFtcGxlLCB3aGVuIHdlIGNvbnZlcnRlZCBgdHZzYCBpbnRvIGEgYHRzYCBvYmplY3QsIHdlIGxvc3QgdGhlIGRheSBjb21wb25lbnQgYmVjYXVzZSBgdHNgIGNvdWxkIG9ubHkgc3RvcmUgdGhlIG1vbnRoIGFuZCB5ZWFyLgoKIyMgQ3JlYXRpbmcgYW4gYG10c2Agb2JqZWN0CgpgYGB7cn0KVVNfaW5kaWNhdG9ycyA8LSBhcnJhbmdlKFVTX2luZGljYXRvcnMsIERhdGUpCgpVU19pbmRpY2F0b3JzX3RzIDwtIHRzKGRhdGEgPSBzZWxlY3QoVVNfaW5kaWNhdG9ycywgYFZlaGljbGUgU2FsZXNgLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBVbmVtcGxveW1lbnQgUmF0ZWApLAogICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gYyh5ZWFyKG1pbih0dnMkRGF0ZSkpLCBtb250aChtaW4odHZzJERhdGUpKSksCiAgICAgICAgICAgICAgICAgICAgICAgZnJlcXVlbmN5ID0gMTIpCgp0c19pbmZvKFVTX2luZGljYXRvcnNfdHMpCmBgYAoKIyMgU2V0dGluZyB0aGUgc2VyaWVzIGZyZXF1ZW5jeQoKU2V0dGluZyB0aGUgZnJlcXVlbmN5IG9mIGEgc2VyaWVzIHNldHMgdGhlIGxlbmd0aCBvZiBhIGN5Y2xlLgoKJCQKXHRleHR7RnJlcXVlbmN5fSA9IFxmcmFje1x0ZXh0e2N5Y2xlIGxlbmd0aH19e1x0ZXh0e3RpbWUgaW50ZXJ2YWwgYmV0d2VlbiBvYnNlcnZhdGlvbn19CiQkCgpJbiB0aGlzIGV4YW1wbGUgd2Ugd2lsbCBzZWUgaG93IHNldHRpbmcgdGhlIGZyZXF1ZW5jeSBpbXBhY3RzIHRoZSBzdHJ1Y3R1cmUgb2YgdGhlIGB0c2Agb2JqZWN0IG91dHB1dC4gRmlyc3QsIHdlIHNpbXVsYXRlIGNsb3NlIHRvIHRlbiB5ZWFycyBvZiBkYWlseSBkYXRhLgoKYGBge3J9CmRhaWx5X2RmIDwtIGRhdGEuZnJhbWUoZGF0ZSA9IHNlcS5EYXRlKGZyb20gPSBhcy5EYXRlKCIyMDEwLTAxLTAxIiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aC5vdXQgPSAzNjUgKiAxMCwgYnkgPSAiZGF5IiksCiAgICAgICAgICAgICAgICAgICAgICAgeSA9IHJub3JtKDM2NSAqIDEwLCBtZWFuID0gMTUsIHNkID0gMikpCgpzdHIoZGFpbHlfZGYpCmBgYAoKQ3JlYXRlIGB0c2Agb2JqZWN0OgoKYGBge3J9CmRheXNfd2Vla190cyA8LSB0cyhkYWlseV9kZiwKICAgICAgICAgICAgICAgICAgIHN0YXJ0ID0gYygxLCB3ZGF5KG1pbihkYWlseV9kZiRkYXRlKSkpLAogICAgICAgICAgICAgICAgICAgZnJlcXVlbmN5ID0gNykKCnRzX2luZm8oZGF5c193ZWVrX3RzKQpgYGAKCiMgRGF0YSBtYW5pcHVsYXRpb24gb2YgYHRzYCBvYmplY3RzCgojIyBUaGUgd2luZG93IGZ1bmN0aW9uCgpUaGUgbWFpbiBwdXJwb3NlIG9mIGEgd2luZG93IGZ1bmN0aW9uIGlzIHRvIHN1YnNldCBhIGB0c2Agb2JqZWN0IGJhc2VkIG9uIGEgdGltZSByYW5nZS4gVGhlIG1haW4gYXJndW1lbnQgb2YgdGhlIGB3aW5kb3coKWAgZnVuY3Rpb24gYXJlIHRoZSBgc3RhcnRgIGFuZCBgZW5kYCBhcmd1bWVudHMuIExldCdzIHVzZSB0aGUgYHdpbmRvdygpYCBmdW5jdGlvbiB0byBleHRyYWN0IGFsbCB0aGUgb2JzZXJ2YXRpb25zIG9mIHRoZSB5ZWFyIDIwMDUgZnJvbSB0aGUgTkdDIHNlcmllczoKCmBgYHtyfQp3aW5kb3cobmdjLCBzdGFydCA9IGMoMjAwNSwgMSksIGVuZCA9IGMoMjAwNSwgNCkpCmBgYAoKV2UgY2FuIGFsc28gZXh0cmFjdCBhIHNwZWNpZmljIGZyZXF1ZW5jeSB1bml0IGZyb20gdGhlIHNlcmllcy4gU2F5IHdlJ3JlIGludGVyZXN0ZWQgaW4gZXh0cmFjdGluZyBhbGwgdGhlIG9ic2VydmF0aW9ucyBvZiB0aGUgc2VyaWVzIHRoYXQgb2NjdXJyZWQgaW4gdGhlIHRoaXJkIHF1YXJ0ZXIgb2YgdGhlIHllYXIuIFRoaXMgY2FuIGJlIGRvbmUgYnkgc2V0dGluZyB0aGUgc3RhcnRpbmcgcG9pbnQgYXQgdGhlIHRoaXJkIHF1YXJ0ZXIgb2YgdGhlIGZpcnN0IHllYXIgYW5kIHRoZSBgZnJlcXVlbmN5YCB0byAxLgoKYGBge3J9CndpbmRvdyhuZ2MsIHN0YXJ0ID0gYygyMDAwLCAzKSwgZnJlcXVlbmN5ID0gMSkKYGBgCgojIyBBZ2dyZWdhdGluZyBgdHNgIG9iamVjdHMKClRoZSBgYWdncmVnYXRlKClgIGZ1bmN0aW9uIHNwbGl0cyB0aGUgZGF0YSBpbnRvIHN1YnNldHMsIGNvbXB1dGVzIHNwZWNpZmljIHN1bW1hcnkgc3RhdGlzdGljcywgYW5kIHRoZW4gYWdncmVnYXRlcyB0aGUgcmVzdWx0cyB0byBhIGB0c2Agb3IgYGRhdGEuZnJhbWVgIG9iamVjdC4gTGV0J3MgdXNlIGBhZ2dyZWdhdGUoKWAgdG8gdHJhbnNmb3JtIHRoZSBOR0Mgc2VyaWVzIGZyb20gYSBxdWFydGVybHkgZnJlcXVlbmN5IHRvIHllYXJseToKCmBgYHtyfQpuZ2NfeWVhcmx5IDwtIGFnZ3JlZ2F0ZShuZ2MsIG5mcmVxdWVuY3kgPSAxLCBGVU4gPSAic3VtIikKbmdjX3llYXJseQpgYGAKCiMjIENyZWF0aW5nIGxhZ3MgYW5kIGxlYWRzIGZvciBgdHNgIG9iamVjdHMKClRoZSBgbGFnKClgIGZ1bmN0aW9uIGZyb20gdGhlICoqc3RhdHMqKiBwYWNrYWdlICh0aGlzIHNob3VsZCBub3QgYmUgY29uZnVzZWQgd2l0aCB0aGUgYGxhZygpYCBmdW5jdGlvbiBmcm9tIHRoZSAqKmRwbHlyKiogcGFja2FnZSkgY2FuIGJlIHVzZWQgdG8gY3JlYXRlIGxhZ3Mgb3IgbGVhZHMgZm9yIGB0c2Agb2JqZWN0cy4KCmBgYHtyfQpuZ2NfbGFnNCA8LSBzdGF0czo6bGFnKG5nYywgayA9IC00KQoKdHNfaW5mbyhuZ2NfbGFnNCkKYGBgCgojIFZpc3VhbGl6aW5nIGB0c2AgYW5kIGBtdHNgIG9iamVjdHMKCiMjIFRoZSBgcGxvdC50cygpYCBmdW5jdGlvbgoKUGxvdHRpbmcgYSBgdHNgIG9iamVjdDoKCmBgYHtyfQpwbG90LnRzKHR2c190cywKICAgICAgICBtYWluID0gIlVTIE1vbnRobHkgVG90YWwgVmVoaWNsZSBTYWxlcyIsCiAgICAgICAgeWxhYiA9ICJUaG91c2FuZHMgb2YgVmVoaWNsZSIsCiAgICAgICAgeGxhYiA9ICJUaW1lIikKYGBgCgpQbG90dGluZyBhbiBgbXRzYCBvYmplY3Q6CgpgYGB7cn0KcGxvdC50cyhVU19pbmRpY2F0b3JzX3RzLAogICAgICAgIHBsb3QudHlwZSA9ICJtdWx0aXBsZSIsCiAgICAgICAgbWFpbiA9ICJVUyBNb250aGx5IFZlaGljbGUgU2FsZXMgdnMuIFVuZW1wbG95bWVudCBSYXRlIiwKICAgICAgICB4bGFiID0gIlRpbWUiKQpgYGAKCiMjIFRoZSAqKmR5Z3JhcGhzKiogcGFja2FnZQoKVGhlICoqZHlncmFwaHMqKiBwYWNrYWdlIGlzIGFuIFIgaW50ZXJmYWNlIHRvIHRoZSBgZHlncmFwaHNgIEphdmFTY3JpcHQgY2hhcnRpbmcgbGlicmFyeS4KCmBgYHtyfQpwX2xvYWQoZHlncmFwaHMpCgpkeWdyYXBoKHR2c190cywKICAgICAgICBtYWluID0gIlVTIE1vbnRobHkgVG90YWwgVmVoaWNsZSBTYWxlcyIsCiAgICAgICAgeWxhYiA9ICJUaG91c2FuZHMgb2YgVmVoaWNsZSIpICU+JSAKICBkeVJhbmdlU2VsZWN0b3IoKQpgYGAKCkZvciB0aGUgYFVTX2luZGljYXRvcnNfdHNgIHNlcmllcywgd2Ugd2lsbCBhZGQgYSBzZWNvbmQgKnkqLWF4aXMsIHdoaWNoIGFsbG93cyB1cyB0byBwbG90IGFuZCBjb21wYXJlIHRoZSB0d28gc2VyaWVzIHRoYXQgYXJlIG5vdCBvbiB0aGUgc2FtZSBzY2FsZToKCmBgYHtyfQpkeWdyYXBoKFVTX2luZGljYXRvcnNfdHMsCiAgICAgICAgbWFpbiA9ICJVUyBNb250aGx5IFZlaGljbGUgU2FsZXMgdnMuIFVuZW1wbG95bWVudCBSYXRlIikgJT4lIAogIGR5QXhpcygieSIsIGxhYmVsID0gIlZlaGljbGUgU2FsZXMiKSAlPiUgCiAgZHlBeGlzKCJ5MiIsIGxhYmVsID0gIlVuZW1wbG95bWVudCBSYXRlIikgJT4lIAogIGR5U2VyaWVzKCJWZWhpY2xlIFNhbGVzIiwgYXhpcyA9ICJ5IiwgY29sb3IgPSAiZ3JlZW4iKSAlPiUgCiAgZHlTZXJpZXMoIlVuZW1wbG95bWVudCBSYXRlIiwgYXhpcyA9ICJ5MiIsIGNvbG9yID0gInJlZCIpICU+JSAKICBkeUxlZ2VuZCh3aWR0aCA9IDQwMCkKYGBgCgojIyBUaGUgVFNzdHVkaW8gcGFja2FnZQoKYGBge3J9CnBfbG9hZChUU3N0dWRpbykKCnRzX3Bsb3QodHZzX3RzLAogICAgICAgIHRpdGxlID0gIlVTIE1vbnRobHkgVG90YWwgVmVoaWNsZSBTYWxlcyIsCiAgICAgICAgWXRpdGxlID0gIlRob3VzYW5kcyBvZiBWZWhpY2xlIiwKICAgICAgICBzbGlkZXIgPSBUUlVFKQpgYGAKCldlIGNhbiBhZGQgYW4gaW50ZXJhY3RpdmUgc2xpZGVyIGZvciB0aGUgKngqLWF4aXMuCgpgYGB7cn0KdHNfcGxvdChVU19pbmRpY2F0b3JzX3RzLAogICAgICAgIHRpdGxlID0gIlVTIE1vbnRobHkgVmVoaWNsZSBTYWxlcyB2cy4gVW5lbXBsb3ltZW50IFJhdGUiLAogICAgICAgIHR5cGUgPSAibXVsdGlwbGUiKQpgYGAK